package com.gitee.wsl.common.chart.sample.line

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PointF
import com.gitee.wsl.android.ui.ext.type.drawLine
import com.gitee.wsl.common.chart.adapter.DataSource
import com.gitee.wsl.common.chart.adapter.SelectItemChartAdapter
import com.gitee.wsl.common.chart.listener.click.PlotPointPosition
import com.gitee.wsl.common.chart.model.DotInfo
import com.gitee.wsl.common.chart.render.background.axis.line.CategoryLineAxis
import com.gitee.wsl.common.chart.render.background.axis.line.DataLineAxis
import com.gitee.wsl.common.chart.render.foreground.PlotCustomLine
import com.gitee.wsl.common.chart.render.shape.plot.renderDot
import com.gitee.wsl.common.chart.sample.line.adapter.LineChartAdapter
import com.gitee.wsl.common.chart.sample.line.model.PointLineData
import com.gitee.wsl.common.ui.draw.type.CurveLineStyle
import com.gitee.wsl.common.ui.draw.type.DotStyle
import com.gitee.wsl.transform.format.Format
import timber.log.Timber


/**
 * @ClassName SplineChart
 * @Description  曲线图基类
 * @author XiongChuanLiang<br/>(xcl_168@aliyun.com)
 *
 */

class PointLineChart(val adapter: LineChartAdapter<PointLineData> = LineChartAdapter()):AbstractLineChart(adapter),
    SelectItemChartAdapter<PointLineData> by adapter {

    //数据源
     var dataSet by DataSource(adapter)

    //分类轴的最大，最小值
     var maxValue = 0.0f
     var minValue = 0.0f

    //用于格式化标签的回调接口
     var labelFormatter: Format<String>? = null

    //平滑曲线
     val lstPoints = mutableListOf<PointF>()
     val bezierPath = Path()

    //key
    //private val mLstKey = mutableListOf<BaseLineData>()

     val lstDotInfo = mutableListOf<DotInfo>()

    //平滑曲线
     var curveLineStyle = CurveLineStyle.BEZIERCURVE

    // 用于绘制定制线(分界线)
     var xAxisCustomLine: PlotCustomLine? = null


    override fun categoryAxisDefaultSetting(categoryAxis: CategoryLineAxis) {
        super.categoryAxisDefaultSetting(categoryAxis)
        categoryAxis.tickMarksAlign=Paint.Align.CENTER
    }

    override fun dataAxisDefaultSetting(dataAxis: DataLineAxis) {
        super.dataAxisDefaultSetting(dataAxis)
        dataAxis.tickMarksAlign=Paint.Align.LEFT
    }

    private fun calcAllPoints(
        bd: PointLineData,
        lstPoints: MutableList<PointF>,
        lstDotInfo: MutableList<DotInfo>,
        dataAxis: DataLineAxis
    ) {
        
        if (maxValue.compareTo(minValue) == -1) {
            Timber.d("轴最大值小于最小值.")
            return
        }
        if (maxValue.compareTo(minValue) == 0) {
            Timber.d("轴最大值与最小值相等.")
            return
        }
        val initX: Float = bodyViewport.left
        val initY: Float = bodyViewport.bottom
        var lineStartX = initX
        var lineStartY = initY
        var lineStopX = 0.0f
        var lineStopY = 0.0f

        //得到标签对应的值数据集
        val chartValues = bd.dataSeries 

        //画出数据集对应的线条
        val count = chartValues.size
        for (i in 0 until count) {
            val entry = chartValues[i]
            lineStopX = getLnXValPosition(entry.x, maxValue, minValue)
            lineStopY = getVPValPosition(entry.y,dataAxis)
            if (0 == i) {
                lineStartX = lineStopX
                lineStartY = lineStopY

                //line
                lstPoints.add(PointF(lineStartX, lineStartY))
                lstPoints.add(PointF(lineStopX, lineStopY))
            } else {
                //line
                lstPoints.add(PointF(lineStopX, lineStopY))
            }

            //dot
            lstDotInfo.add(DotInfo(entry.x, entry.y, lineStopX, lineStopY))
            lineStartX = lineStopX
            lineStartY = lineStopY
        }
    }


    private fun drawLine(
        canvas: Canvas, spData: PointLineData,
        lstPoints: List<PointF>
    ): Boolean {
        val count = lstPoints.size
        for (i in 0 until count) {
            if (0 == i) continue
            val pointStart = lstPoints[i - 1]
            val pointStop = lstPoints[i]
            canvas.drawLine(spData.lineSpacingStyle, pointStart.x, pointStart.y, pointStop.x, pointStop.y, spData.dotLinePaint)
        }
        return true
    }

    private fun drawBezierCurveLine(
        canvas: Canvas, bezierPath: Path,
        spData: PointLineData, lstPoints: List<PointF>
    ): Boolean {
        drawBezierCurveLine(canvas, spData.dotLinePaint, bezierPath, lstPoints)
        return true
    }

    private fun drawDotAndLabel(
        canvas: Canvas, spData: PointLineData, dataID: Int,
        lstPoints: List<PointF>
    ): Boolean {
        val pLine = spData.plotLine
        if (pLine.dotStyle == DotStyle.HIDE && !spData.isLabelVisible) {
            return true
        }
        val itemAngle = spData.itemLabelRotateAngle
        val pDot = pLine.plotDot
        val radius = pDot.dotRadius
        val count = lstDotInfo.size
        for (i in 0 until count) {
            val dotInfo = lstDotInfo[i]
            if (pLine.dotStyle != DotStyle.HIDE) {
                canvas.renderDot(pDot, dotInfo.x, dotInfo.y, pLine.dotPaint) //标识图形
                savePointRecord(
                    dataID, i,
                    dotInfo.x + moveX, dotInfo.y + moveY,
                    dotInfo.x - radius + moveX,
                    dotInfo.y - radius + moveY,
                    dotInfo.x + radius + moveX,
                    dotInfo.y + radius + moveY
                )
                //childID++;
            }

            //Log.e("spchart","dataID:"+Float.toString(dataID));
            //Log.e("spchart","  I:"+Integer.toString(i));
            //显示批注形状
            drawAnchor(anchorSet, dataID, i, canvas, dotInfo.x, dotInfo.y, radius)
            if (spData.isLabelVisible) {
                //请自行在回调函数中处理显示格式
                spData.plotLabel.renderLabel(
                    canvas, pLine.dotLabelPaint,
                    labelFormatter?.invoke(dotInfo.label)?:dotInfo.label,
                    dotInfo.x, dotInfo.y, itemAngle, spData.lineColor
                )
            }
        }
        adapter.isRecordSetInited = true
        return true
    }


    /**
     * 绘制图
     */
    private fun drawPlot(canvas: Canvas, dataAxis: DataLineAxis): Boolean {
        //检查是否有设置分类轴的最大最小值
        if (maxValue.compareTo(minValue) == 0 && 0.0.compareTo(maxValue) == 0
        ) {
            Timber.d("请检查是否有设置分类轴的最大最小值。")
            return false
        }

        //开始处 X 轴 即分类轴
        val count = dataSet.size
        for (i in 0 until count) {
            val spData = dataSet[i]
            calcAllPoints(spData, lstPoints, lstDotInfo,dataAxis)
            when (curveLineStyle) {
                CurveLineStyle.BEZIERCURVE ->
                    drawBezierCurveLine(canvas, bezierPath, spData, lstPoints)
                CurveLineStyle.BEELINE ->
                    drawLine(canvas, spData, lstPoints)
                else -> {
                    Timber.d("未知的枚举类型.")
                    continue
                }
            }
            drawDotAndLabel(canvas, spData, i, lstPoints)
            lstKey.add(dataSet[i])
            lstDotInfo.clear()
            lstPoints.clear()
            bezierPath.reset()
        }

        return true
    }


    /////////////////////////////////////////////

    /////////////////////////////////////////////
    override fun drawClipPlot(canvas: Canvas, dataAxis:DataLineAxis, categoryAxis: CategoryLineAxis) {
        if (drawPlot(canvas,dataAxis)) {
            if (null != customLine) //画横向定制线
            {
                customLine!!.setVerticalPlot(dataAxis, plotViewport, getPlotScreenHeight())
                customLine!!.renderVerticalCustomlinesDataAxis(canvas)
            }
            xAxisCustomLine?.renderCategoryAxisCustomlines(
                canvas,
                getPlotScreenWidth(), plotViewport,
                maxValue, minValue
            )
        }
    }

     fun savePointRecord(
        dataID: Int, childID: Int,
        x: Float, y: Float, left: Float, top: Float, right: Float, bottom: Float
    ) {
        if(adapter.isRecordSetInited) return
        val pRecord = PlotPointPosition()
        pRecord.savePlotDataID(dataID)
        pRecord.savePlotDataChildID(childID)
        pRecord.savePlotPosition(x, y)
        pRecord.savePlotRectF(left, top, right, bottom)
        //pRecord.extPointClickRange(clickRangeExtValue)
        adapter.addRecordItem(pRecord)
    }

    protected override fun drawClipLegend(canvas: Canvas) {
        //图例
        //plotLegend.renderLineKey(canvas, mLstKey)
        //mLstKey.clear()
    }
    /////////////////////////////////////////////
}